import {
  IPublicTypeCompositeArray,
  IPublicTypeCompositeObject,
  IPublicTypeCompositeValue,
  IPublicTypeJSExpression,
  IPublicTypeJSFunction,
  IPublicTypeJSONArray,
  IPublicTypeJSONObject,
  IPublicTypeJSSlot,
  IPublicTypeNodeDataType,
  IPublicTypeNodeSchema,
} from '@alilc/lowcode-types';

/**
 * 作用域定义，维护作用域内定义，支持作用域链上溯
 */
export interface IScope {
  // 父级作用域（如果是根作用域则为 null）
  readonly parent: IScope | null;

  // 作用域内定义的变量/函数等 bindings
  readonly bindings?: IScopeBindings;

  refNames: string[];

  // TODO: 需要有上下文信息吗？ 描述什么内容
  createSubScope: (ownIndentifiers: string[]) => IScope;
}

export interface IScopeBindings {
  readonly parent: IScopeBindings | null;

  hasBinding: (varName: string) => boolean;
  hasOwnBinding: (varName: string) => boolean;

  addBinding: (varName: string) => void;
  removeBinding: (varName: string) => void;

  getAllBindings: () => string[];
  getAllOwnedBindings: () => string[];
}

export class ParseError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'ParseError';
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

export class TransformError extends Error {
  constructor(message: string, cause?: Error) {
    super(message);
    this.name = 'TransformError';
    this.cause = cause;
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

/* eslint-disable @typescript-eslint/no-useless-constructor */
export class CodeGeneratorError extends Error {
  readonly detail?: unknown;

  constructor(message: string, detail?: unknown) {
    super(message);
    this.name = this.constructor.name;
    this.detail = detail;
    Object.setPrototypeOf(this, new.target.prototype);
  }
}

export class ComponentValidationError extends CodeGeneratorError {}

export class CompatibilityError extends CodeGeneratorError {}

export class PublisherError extends CodeGeneratorError {}

export enum PIECE_TYPE {
  BEFORE = 'NodeCodePieceBefore',
  TAG = 'NodeCodePieceTag',
  ATTR = 'NodeCodePieceAttr',
  CHILDREN = 'NodeCodePieceChildren',
  AFTER = 'NodeCodePieceAfter',
}

export interface CodePiece {
  name?: string;
  value: string;
  type: PIECE_TYPE;
  isJSExpression?: boolean;
}

export type NodeGenerator<T> = (
  nodeItem: IPublicTypeNodeDataType,
  scope: IScope,
  config?: CompositeValueGeneratorOptions,
) => T;

export interface AttrData {
  attrName: string;
  attrValue: IPublicTypeCompositeValue;
}
// 对 JSX 出码的理解，目前定制点包含【包装】【标签名】【属性】
export type AttrPlugin = BaseGenerator<AttrData, CodePiece[], NodeGeneratorConfig>;
export type NodePlugin = BaseGenerator<IPublicTypeNodeSchema, CodePiece[], NodeGeneratorConfig>;

export interface NodeGeneratorConfig {
  handlers?: HandlerSet<string>;
  tagMapping?: (input: string) => string;
  attrPlugins?: AttrPlugin[];
  nodePlugins?: NodePlugin[];
  self?: NodeGenerator<string>;

  /**
   * 是否要容忍对 JSExpression 求值时的异常
   * 默认：true
   * 注：如果容忍异常，则会在求值时包裹 try-catch 块 -- 通过 __$$eval / __$$evalArray
   *     catch 到异常时默认会抛出一个 CustomEvent 事件里面包含异常信息和求值的表达式
   */
  tolerateEvalErrors?: boolean;
}

export type BaseGenerator<I, T, C> = (
  input: I,
  scope: IScope,
  config?: C,
  next?: BaseGenerator<I, T, C>,
) => T;

export interface HandlerSet<T> {
  string?: CompositeTypeGenerator<string, T>;
  boolean?: CompositeTypeGenerator<boolean, T>;
  number?: CompositeTypeGenerator<number, T>;
  expression?: CompositeTypeGenerator<IPublicTypeJSExpression, T>;
  function?: CompositeTypeGenerator<IPublicTypeJSFunction, T>;
  slot?: CompositeTypeGenerator<IPublicTypeJSSlot, T>;
  array?: CompositeTypeGenerator<IPublicTypeJSONArray | IPublicTypeCompositeArray, T>;
  object?: CompositeTypeGenerator<IPublicTypeJSONObject | IPublicTypeCompositeObject, T>;
}

type CompositeTypeGenerator<I, T> =
  | BaseGenerator<I, T, CompositeValueGeneratorOptions>
  | Array<BaseGenerator<I, T, CompositeValueGeneratorOptions>>;

export interface CompositeValueGeneratorOptions {
  handlers?: HandlerSet<string>;
  nodeGenerator?: NodeGenerator<string>;
  tolerateEvalErrors?: boolean;
  /**
   * 是否是属性值，用于特殊处理循环变量引用
   */
  isAttrValue?: boolean;
  /**
   * 当前循环项的变量名，用于替换this.loopItemName
   */
  loopItemName?: string;
  /**
   * 当前循环索引的变量名，用于替换this.loopIndexName
   */
  loopIndexName?: string;
  /**
   * 是否保留循环变量的this引用
   */
  preserveThisForLoopVars?: boolean;
  /**
   * 属性名称，用于特殊处理事件处理函数
   */
  attrName?: string;
  /**
   * 是否是JSSlot参数，用于特殊处理JSSlot参数引用
   */
  isJSSlotParams?: boolean;
  /**
   * 是否保留JSSlot参数的this前缀
   */
  preserveThisForSlotParams?: boolean;
}

export interface INpmPackage {
  package: string; // 组件包的名称
  version: string; // 组件包的版本
}

/**
 * 外部依赖描述
 *
 * @export
 * @interface IExternalDependency
 */
export interface IExternalDependency extends INpmPackage, IDependency {}

export enum InternalDependencyType {
  PAGE = 'pages',
  BLOCK = 'components',
  COMPONENT = 'components',
  UTILS = 'utils',
}

export enum DependencyType {
  External = 'External',
  Internal = 'Internal',
}

export interface IInternalDependency extends IDependency {
  type: InternalDependencyType;
  moduleName: string;
}

export interface IDependency {
  destructuring: boolean; // 组件是否是解构方式方式导出
  exportName: string; // 导出命名
  subName?: string; // 下标子组件名称
  main?: string; // 包导出组件入口文件路径 /lib/input
  dependencyType?: DependencyType; // 依赖类型 内/外
  componentName?: string; // 导入后名称
}

export interface TransformResult {
  hasError: boolean;
  errorInfo?: string;
  code?: string;
  errorLocation?: {
    line: number;
    column: number;
  };
}
